import {_decorator, find, isValid} from "cc";
import {ResourceUtil} from "../utils/ResourceUtil";
import {BaseRouteConstants} from "../constant/BaseRouteConstants";

const {ccclass, property} = _decorator;

@ccclass("UIManager")
export class UIManager {
    /**
     * 可展示界面
     */
    private _dictUI: any = {}

    /**
     * 正在加载的界面或不存在的界面
     */
    private _dictLoadingUI: any = {}

    /**
     * 检查当前UI是否正在展示
     * @param uiPath UI路径
     */
    public isVisible(uiPath: string) {
        if (!this._dictUI.hasOwnProperty(uiPath)) {
            return false;
        }

        let ui = this._dictUI[uiPath];
        return isValid(ui) && ui.active && ui.parent;
    }

    /**
     * 获取UI父级节点
     * @param uiPath
     * @private
     */
    private findUiParent(uiPath: string) {
        if (uiPath && uiPath.indexOf(BaseRouteConstants.LAYOUT.TIP) !== -1) {
            return find(BaseRouteConstants.LAYOUT.TIP);
        } else if (uiPath && uiPath.indexOf(BaseRouteConstants.LAYOUT.DIALOG) !== -1) {
            return find(BaseRouteConstants.LAYOUT.DIALOG);
        } else {
            return find(BaseRouteConstants.LAYOUT.PANEL);
        }
    }

    /**
     * 加载UI组件
     * @param uiPath UI路径
     * @param args 参数
     * @param cb 回调
     * @private
     */
    private loadUiComponent(uiPath: string, args?: any, cb?: Function) {
        // 获取当前界面信息
        let ui = this._dictUI[uiPath];
        // 拆分界面路径，获取界面名字
        let nameIndex = uiPath.lastIndexOf('/');
        // 获取预制体名称
        let prefabName = uiPath.slice(nameIndex + 1);
        // 根据UI组件名称尝试获取UI组件，忽略首字母大小写
        let uiComponentNames = [prefabName, prefabName.charAt(0).toUpperCase() + prefabName.slice(1)];
        // 遍历获取
        for (let uiComponentName of uiComponentNames) {
            // 尝试获取UI组件
            let uiComponent = ui.getComponent(uiComponentName);
            // 脚本文件不存在
            if (!uiComponent) {
                console.warn(`查找不到脚本文件${prefabName}`);
            }

            // 脚本文件不存在show方法
            if (!uiComponent.show) {
                console.warn(`当前脚本文件${prefabName}内部不存在show方法`);
            }

            // 组件存在，且组件中存在show方法，则进行回调
            if (uiComponent && uiComponent.show) {
                uiComponent.show.apply(uiComponent, args);
                cb && cb(uiComponent);
                return;
            }
        }
    }

    /**
     * 显示UI
     * @param {String} uiPath UI路径
     * @param {Array} args 参数
     * @param {Function} cb 回调函数，创建完毕后回调
     */
    public show(uiPath: string, args?: any, cb?: Function) {
        // 如果当前界面正在加载中，则直接返回，避免重复创建
        if (this._dictLoadingUI[uiPath]) {
            return;
        }

        // 获取父级节点
        let parentNode = this.findUiParent(uiPath);
        if (!parentNode) {
            throw `尝试读取节点${uiPath}的父级节点失败！`;
        }

        // 在已存在的节点中重新唤起，避免对象的重新创建
        if (this._dictUI.hasOwnProperty(uiPath)) {
            // 获取当前界面信息
            let ui = this._dictUI[uiPath];
            // 节点是否存在
            if (isValid(ui)) {
                ui.parent = parentNode;
                ui.active = true;
                // 加载UI
                this.loadUiComponent(uiPath, args, cb);
                return;
            }
        }

        // 如果当前界面不存在，则标记当前界面为加载中状态
        this._dictLoadingUI[uiPath] = true;
        // 创建目标界面
        ResourceUtil.createUI(uiPath, (err: any, node: any) => {
            // 创建UI异常
            if (err) {
                console.error(err);
                return;
            }

            this._dictUI[uiPath] = node;
            // 设置组件父级节点，并展示
            node.parent = parentNode;
            node.active = true;
            // 加载UI
            this.loadUiComponent(uiPath, args, cb);
            // 判断是否有可能在显示前已经被关掉了？如刚打开，正在加载，但有触发关闭，则会出现响应不及时的问题
            if (!this._dictLoadingUI[uiPath]) {
                //如果在显示前又被关闭，则直接触发关闭掉
                this.hide(uiPath);
            } else {
                // 界面已加载完成
                this._dictLoadingUI[uiPath] = false;
            }

        });
    }

    /**
     * 隐藏单例界面
     * @param {String} uiPath
     * @param {fn} cb
     */
    public hide(uiPath: string, cb?: Function) {
        // 判断界面是否存在
        if (this._dictUI.hasOwnProperty(uiPath)) {
            // 获取界面节点
            let ui = this._dictUI[uiPath];
            // 节点未销毁
            if (ui && isValid(ui)) {
                // 尝试获取动画组件
                let ani = ui.getComponent('animationUI');
                // 若存在动画组件，则执行动画关闭逻辑
                if (ani) {
                    ani.close(() => {
                        ui.parent = null;
                        if (cb && typeof cb === 'function') {
                            cb();
                        }
                    });
                } else {
                    ui.parent = null;
                    if (cb && typeof cb === 'function') {
                        cb();
                    }
                }
            } else if (cb && typeof cb === 'function') {
                cb();
            }
        }

        this._dictLoadingUI[uiPath] = false;
    }
}
